#include "UdpClient.hpp"
#include "Common.hpp"
#include<iostream>
#include<cstdlib>
#include<memory>
#include<string.h>

//我得拿到服务器的IP号和端口号，可以在main函数的参数中
//永远是客服端先主动，服务器是被动，这种是cs模式。
//  ./client_udp serverip serverport
int main(int argc,char* argv[]) 
{
    std::cout<<"我是客户端"<<std::endl;
    if(argc!=3) 
    {
        std::cerr<<"Usage: "<<argv[0]<<"serverip serverport"<<std::endl;
        Die(USAGE_ERR);
    }
    std::string serverip=argv[1];
    uint16_t serverport=std::stoi(argv[2]);

    //1.创建socket套接字
    int sockfd=::socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd<0)
    {
        std::cerr<<"socket error"<<std::endl;
        Die(SOCKET_ERR);
    }

    //1.1填充server信息
    struct sockaddr_in server;
    bzero(&server,sizeof(server));//初始清零结构体。
    server.sin_family=AF_INET;
    server.sin_port=htons(serverport);
    server.sin_addr.s_addr=::inet_addr(serverip.c_str());

    //2.client done
    while(true)
    {
        std::cout<<" Please Enter# ";
        std::string message;
        std::getline(std::cin,message);
        //client 不需要绑定吗   
        //客户端必须也要有自己的ip和端口！但是客户端不需要自己显示的调用bind!!!
        //而是客户端首次发送sendto消息时候，由OS自动进行bind。
        
        //如何理解client自动bind。2.如何理解server要显示的bind?
        
        int n=::sendto(sockfd,message.c_str(),message.size(),0,const_cast<struct sockaddr*>(CONV(&server)),sizeof(server));
        //安全性上来讲每一次调用一个函数就要判断返回值，看函数是否成功。
        //这里为了偷懒就不判断了
        (void)n;//进行一次操作不然编译器会报警告。

        struct sockaddr_in temp;
        socklen_t len=sizeof(temp);
        char buffer[1024];
        n=::recvfrom(sockfd,buffer,sizeof(buffer)-1,0,const_cast<struct sockaddr*>(CONV(&temp)),&len);
        //这里的服务器的信息不能省略，
        //因为还可以访问多个服务器但是你只传了一个服务器的ip和端口号。
        if(n>0)
        {
            buffer[n]=0;
            std::cout<<buffer<<std::endl; 
        }
    }
    return 0;
}